home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- *
- * setver.c Serialize an .EXE File
- *
- * This program will insert user-defined serial and version numbers
- * into the .EXE program file specified. It is not intended to be
- * used with .COM programs and will not work with anything other than
- * .EXE files. This is guaranteed by forcing the extension to .EXE.
- *
- * The program operates by searching through the target file for the
- * copyright message. Once found, the serial number block is located
- * after the null byte of the copyright message. The copyright
- * message is limited to MAXCPMSG, which is currently 1024 bytes.
- *
- * Once the serial number block is located, the binary serial number
- * is inserted after swapping bytes 2 and 4. Following this is the
- * two-byte version number, and then a checksum byte that spans both
- * the copyright message and the serial/version numbers. The checksum
- * is calculated by XORing each byte MOD 256. While simple to calculate,
- * this method is difficult to decipher.
- *
- * This program must be linked with the file SERNO.ASM, which is also
- * used with any target program that is to be serialized. It is intended
- * to be compiled using Microsoft C V5.1 or later.
- *
- * The command-line format is:
- *
- * SETVER <program filename> [-sSerial_Number] [-vVersion_Number]
- *
- * The <program filename> may be any valid DOS pathname. The extension
- * will be forced to .EXE. The [serial number] may be any numeric string
- * of one to nine digits, and is optional. If omitted, it will default
- * to zero. The [version number] may be any numeric string of up to five
- * digits, provided that the integer value is less than 65536. It is
- * optional and will default to zero if omitted. Alpha characters are
- * not allowed in the serial or version numbers. If both the serial AND
- * version numbers are omitted, any serial and version numbers in the
- * file will be displayed.
- *
- * Arguments may be specified in any order.
- *
- *************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <limits.h>
- #include <string.h>
- #include <ctype.h>
-
- /*#page*******************************************************************
- *
- * Constants
- *
- *************************************************************************/
-
- #define MAXCPMSG 1024 /* maximum copyright message length */
- #define MAXPATH 128 /* maximum length of pathname */
-
- /*************************************************************************
- *
- * Serial Number Block (follows NULL on copyright message)
- *
- *************************************************************************/
-
- #pragma pack(1)
-
- typedef union __sn_t {
- long sni; /* integer serial number */
- char snb [sizeof (long)]; /* component bytes */
- } sn_t;
-
- typedef struct __sn_block_t {
- sn_t SN_Data; /* serial number */
- unsigned int VN_Data; /* version number */
- char SN_Cksm; /* copyright/number checksum */
- char EXE_Cksm; /* .EXE file checksum correction */
- } sn_block_t;
-
- /*#page*******************************************************************
- *
- * .EXE File Header Structure
- *
- *************************************************************************/
-
- typedef struct __exe_hdr_t {
- int MagicNumber;
- int LastPageSize;
- int PagesInFile;
- int NumberRelocations;
- int HeaderParagraphs;
- int ParagraphsNeeded;
- int ParagraphsWanted;
- int InitialSS;
- int InitialSP;
- int WordChecksum;
- int InitialIP;
- int InitialCS;
- int FirstRelocation;
- int OverlayNumber;
- } exe_hdr_t;
-
- /*************************************************************************
- *
- * External Functions Provided by 'serno.asm'
- *
- *************************************************************************/
-
- extern char far *_CPPTR (void); /* get far pointer to copyright message */
- extern int _CPSUM (char far *p); /* calculate XOR checksum */
-
- /*************************************************************************
- *
- * Local Function Prototypes
- *
- *************************************************************************/
-
- void main (int argc, char **argv);
- int InsertNumbers (long pos, sn_t sn, unsigned int vn);
- int MoveTo (long pos);
- int ConvertSerialNum (char *cp, sn_t *sn);
- int ConvertVersionNum (char *cp, unsigned int *vn);
- int ConvertPathName (char *src, char *dst);
- long LocateCopyright (void);
- long LoadCopyright (long pos);
- void DisplayNumbers (long pos);
-
- /*#page*******************************************************************
- *
- * Variables
- *
- *************************************************************************/
-
- FILE *fp; /* .EXE file pointer */
- char TargetName [MAXPATH+1]; /* .EXE file pathname */
- sn_block_t *sn_block; /* serial number block */
- char *CpMsgPtr; /* pointer to copyright message */
-
- /*#page*******************************************************************
- *
- * SETVER Main
- *
- *************************************************************************/
-
- void main (argc, argv)
- int argc;
- char *argv [];
- {
- sn_t sn;
- unsigned int vn;
- long pos;
- char gotfile, display, *cp;
- int arg;
-
- fprintf (stderr, "EXE Program File Distribution Setup Utility Version 1.00\n");
- fprintf (stderr, "Copyright (c) 1988 Quid Pro Quo Software. All rights reserved.\n");
-
- /* set up default numbers */
-
- sn.sni = 0L;
- vn = 0;
-
- /* parse command line */
-
- display = 1;
- gotfile = 0;
- for (arg = 1; arg < argc; ++arg)
- {
- if (*(cp = argv [arg]) == '-')
- {
- /* then serial or version number */
-
- display = 0;
- ++cp;
- if (toupper (*cp) == 'S')
- {
- /* convert desired serial number to binary */
-
- if (! ConvertSerialNum (++cp, &sn))
- exit (1);
- }
- else if (toupper (*cp) == 'V')
- {
- /* convert desired version number to binary */
-
- if (! ConvertVersionNum (++cp, &vn))
- exit (1);
- }
- else
- {
- fprintf (stderr, "Unknown argument: %s\n", argv [arg]);
- exit (1);
- }
- }
-
- else if (! gotfile)
- {
- /* not switch - must be program filename */
-
- if (! ConvertPathName (cp, TargetName))
- exit (1);
- gotfile = 1;
- }
- else
- {
- fprintf (stderr, "More than one program filename specified\n");
- exit (1);
- }
- }
-
- if (! gotfile)
- {
- fprintf (stderr, "\nUsage: SETVER <.EXE Program Name> [-sSerialNumber] [-vVersionNumber]\n");
- exit (1);
- }
-
- /* open the target file */
-
- if ((fp = fopen (TargetName, "rb+")) == NULL)
- {
- fprintf (stderr, "\nCannot open file %s\n", TargetName);
- exit (1);
- }
-
- /* locate the copyright message */
-
- if ((pos = LocateCopyright ()) == 0L)
- {
- fclose (fp);
- exit (1);
- }
-
- /* check for modification or display mode */
-
- if (display)
- DisplayNumbers (pos);
-
- else if (! InsertNumbers (pos, sn, vn))
- {
- fclose (fp);
- exit (1);
- }
-
- /* close the target file */
-
- fclose (fp);
- if (! display)
- fprintf (stderr, "\nProgram file %s successfully modified.\n", TargetName);
-
- exit (0);
- }
-
- /*#page*******************************************************************
- *
- * Insert Serial Number
- *
- * This function will insert the passed serial number into the target
- * file. It first loads the copyright message and serial number block,
- * and then writes the serial number into the buffer. The checksum
- * is then calculated on the buffer, the .EXE checksum is corrected,
- * and the serial number block is rewritten to the file.
- *
- * Synopsis:
- *
- * rc = InsertNumbers (pos, sn, vn);
- *
- * int rc; true if numbers successfully written
- * long pos; file offset to copyright message
- * sn_t sn; serial number to insert
- * unsigned int vn; version number to insert
- *
- *************************************************************************/
-
- int InsertNumbers (pos, sn, vn)
- long pos;
- sn_t sn;
- unsigned int vn;
- {
- char *cp;
- int x;
- unsigned char sum;
-
- /* allocate memory and read the copyright message and serial
- number block */
-
- if ((pos = LoadCopyright (pos)) == 0L)
- return (0);
-
- /* swap bytes two and four and insert the serial number */
-
- x = sn.snb [1];
- sn.snb [1] = sn.snb [3];
- sn.snb [3] = (char) x;
- sn_block->SN_Data.sni = sn.sni;
-
- /* insert the version number */
-
- sn_block->VN_Data = vn;
-
- /* now calculate the copyright and serial/version number XOR checksum */
-
- sn_block->SN_Cksm = (char) _CPSUM ((char far *) CpMsgPtr);
-
- /* now do a standard byte checksum on the serial number and XOR sum */
-
- for (x = sum = 0; x < (sizeof (sn_block_t) - 1); ++x)
- sum += (unsigned char) *cp++;
-
- /* calculate the value needed for a zero .EXE checksum and insert it */
-
- sn_block->EXE_Cksm = (char) (0x100 - (unsigned int) sum);
-
- /* write the serial number block back to the file */
-
- if (! MoveTo (pos))
- return (0);
-
- if (fwrite ((char *) sn_block, 1, sizeof (sn_block_t), fp) < sizeof (sn_block_t))
- {
- fprintf (stderr, "\nUnable to rewrite serial number block to file %s\n", TargetName);
- return (0);
- }
-
- /* release the work buffer */
-
- free (CpMsgPtr);
- return (1);
- }
-
- /*#page*******************************************************************
- *
- * Display Serial and Version Numbers
- *
- * This function will display the serial and version numbers that
- * exist in the target file. If the serial or version number is
- * invalid, an error message will be displayed. It is assumed that
- * serial and version numbers of zero indicate that the file has not
- * been serialized; otherwise, tampering will be assumed.
- *
- * This function will not alter the target file.
- *
- * Synopsis:
- *
- * DisplayNumbers (pos);
- *
- * long pos; file offset to copyright message
- *
- *************************************************************************/
-
- void DisplayNumbers (pos)
- long pos;
- {
- int x;
- unsigned int vn;
-
- /* read the copyright message and serial number block */
-
- if ((pos = LoadCopyright (pos)) != 0L)
- {
- /* verify the copyright and serial number checksum */
-
- if ((char) (x = _CPSUM ((char far *) CpMsgPtr)) == sn_block->SN_Cksm)
- {
- printf ("\nProgram File %s:\nCopyright: \"%s\"\n", TargetName, CpMsgPtr);
-
- /* swap bytes two and four and display the serial number */
-
- x = sn_block->SN_Data.snb [1];
- sn_block->SN_Data.snb [1] = sn_block->SN_Data.snb [3];
- sn_block->SN_Data.snb [3] = (char) x;
-
- printf ("Serial Number: %ld\n", sn_block->SN_Data.sni);
-
- /* display the version number */
-
- vn = sn_block->VN_Data;
- printf ("Version Number: V%u.%02u\n", vn/100, vn%100);
- }
-
- else if (sn_block->SN_Data.sni == 0L &&
- sn_block->VN_Data == 0 &&
- sn_block->SN_Cksm == 0 &&
- sn_block->EXE_Cksm == 0)
- printf ("\nFile %s has not been serialized.\n", TargetName);
-
- else
- printf ("\nWARNING: PROGRAM FILE %s HAS BEEN ALTERED\n", TargetName);
-
- free (CpMsgPtr);
- }
- }
-
- /*#page*******************************************************************
- *
- * Read Copyright Message and Serial Number Block
- *
- * This function will allocate memory for the copyright message and
- * the serial number block, and then read this information into the
- * allocated buffer at the position given by the input argument.
- * It returns the file offset of the serial number block if the
- * data are successfully read, or 0L if an error occurs.
- *
- * The global pointer CpMsgPtr is set to point to the copyright
- * message read from the file, and the global pointer sn_block
- * points to the serial number block.
- *
- * Synopsis:
- *
- * pos = LoadCopyright (pos);
- *
- * long pos; file offset of serial number block
- *
- *************************************************************************/
-
- long LoadCopyright (pos)
- long pos;
- {
- char *cp;
- int c;
-
- /* allocate a buffer and read the copyright data into it */
-
- if ((CpMsgPtr = malloc ((unsigned int) (MAXCPMSG + sizeof (sn_block_t) + 1))) == NULL)
- {
- fprintf (stderr, "\nInsufficient memory\n");
- return (0L);
- }
-
- if (! MoveTo (pos))
- return (0L);
-
- /* read copyright message into buffer */
-
- for (cp = CpMsgPtr; cp < &CpMsgPtr [MAXCPMSG] && (c = fgetc (fp)) != EOF && (char) c != '\0'; *cp++ = (char) c)
- ;
-
- if (c == EOF)
- {
- fprintf (stderr, "\nUnexpected EOF; unterminated copyright message\n");
- return (0L);
- }
-
- if ((char) c != '\0')
- {
- fprintf (stderr, "\nCopyright message exceeds maximum of %d characters\n", MAXCPMSG);
- return (0L);
- }
-
- /* save the null byte in the buffer, and save the location of the
- serial number block */
-
- *cp++ = (char) c;
- sn_block = (sn_block_t *) cp;
-
- /* save the current file position; we need only rewrite the serial
- number block */
-
- if ((pos = ftell (fp)) < 0L)
- {
- fprintf (stderr, "\nUnable to determine serial number block offset\n");
- return (0L);
- }
-
- /* now read the serial number and checksum block */
-
- if (fread (cp, 1, sizeof (sn_block_t), fp) != sizeof (sn_block_t))
- {
- fprintf (stderr, "\nUnable to read serial number block from file %s\n", TargetName);
- return (0L);
- }
-
- return (pos);
- }
-
- /*#page*******************************************************************
- *
- * Seek To File Offset
- *
- * This function will seek to the specified position in the target
- * file. If the seek fails, an error message will be written to the
- * console and the function will return false. If the seek succeeds,
- * then TRUE is returned.
- *
- * Synopsis:
- *
- * rc = MoveTo (pos);
- *
- * int rc; true if successful seek, else false
- * long pos; desired file position
- *
- *************************************************************************/
-
- int MoveTo (pos)
- long pos;
- {
- if (fseek (fp, pos, SEEK_SET) != 0)
- {
- fprintf (stderr, "\nSeek error on file %s\n", TargetName);
- return (0);
- }
- return (1);
- }
-
- /*#page*******************************************************************
- *
- * Convert Serial Number to Binary
- *
- * This function will convert the passed serial number string to
- * binary and insert it into the serial number structure. It will
- * return TRUE if the serial number is valid, else FALSE.
- *
- * Synopsis:
- *
- * rc = ConvertSerialNum (cp, sn);
- *
- * int rc; nonzero if valid serial number
- * char *cp; pointer to serial number string
- * sn_t *sn; pointer to serial number union
- *
- *************************************************************************/
-
- int ConvertSerialNum (cp, sn)
- char *cp;
- sn_t *sn;
- {
- char *p;
-
- for (p = cp; *p && isdigit (*p); ++p)
- ;
- if (*p)
- {
- fprintf (stderr, "\nSerial number contains non-numeric characters.\n");
- return (0);
- }
-
- if (strlen (cp) > 9)
- {
- fprintf (stderr, "\nSerial number contains too many digits.\n");
- return (0);
- }
-
- sn->sni = atol (cp);
- return (1);
- }
-
- /*#page*******************************************************************
- *
- * Convert Version Number to Binary
- *
- * This function will convert the passed version number string to
- * binary and insert it into the passed version number variable. It
- * will return TRUE if the version number is valid, else FALSE.
- *
- * Synopsis:
- *
- * rc = ConvertVersionNum (cp, vn);
- *
- * int rc; nonzero if valid version number
- * char *cp; pointer to version number string
- * unsigned int *vn; pointer to version number variable
- *
- *************************************************************************/
-
- int ConvertVersionNum (cp, vn)
- char *cp;
- unsigned int *vn;
- {
- long x;
- char *p;
-
- for (p = cp; *p && isdigit (*p); ++p)
- ;
- if (*p)
- {
- fprintf (stderr, "\nVersion number contains non-numeric characters.\n");
- return (0);
- }
-
- if (strlen (cp) > 5)
- {
- fprintf (stderr, "\nVersion number contains too many digits.\n");
- return (0);
- }
-
- if ((x = atol (cp)) > UINT_MAX)
- {
- fprintf (stderr, "\nVersion number is greater than %u.\n", UINT_MAX);
- return (0);
- }
-
- *vn = (unsigned int) x;
- return (1);
- }
-
- /*#page*******************************************************************
- *
- * Verify and Save Pathname
- *
- * This function will verify that the passed pathname either has no
- * extension or has an .EXE extension. If there is no extension, then
- * .EXE will be appended.
- *
- * Synopsis:
- *
- * rc = ConvertPathName (src, dst);
- *
- * int rc; true if valid pathname
- * char *src; source pathname
- * char *dst; destination buffer
- *
- *************************************************************************/
-
- int ConvertPathName (src, dst)
- char *src, *dst;
- {
- char *cp;
- static char exe_ext [] = { ".EXE" };
-
- strcpy (dst, src);
- strupr (dst);
- if ((cp = strchr (src, exe_ext [0])) == NULL)
- strcat (dst, exe_ext);
- else if (strnicmp (cp, exe_ext, strlen (exe_ext)) != 0)
- {
- fprintf (stderr, "\n%s is not a valid pathname.\n", dst);
- return (0);
- }
- return (1);
- }
-
- /*#page*******************************************************************
- *
- * Locate Copyright Message
- *
- * This function will search the target .EXE file for the copyright
- * message pointed to by _CPPTR(). If found, it returns the offset
- * in the file; otherwise, it returns NULL. The file pointer is
- * a global variable.
- *
- * Synopsis:
- *
- * pos = LocateCopyright ();
- *
- * long pos; file position or NULL if not found
- *
- *************************************************************************/
-
- long LocateCopyright ()
- {
- exe_hdr_t Header;
- char far *p, far *cp;
- long pos;
- int c;
-
- /* read .EXE header */
-
- if (fread ((char *) &Header, 1, sizeof (Header), fp) != sizeof (Header))
- {
- fprintf (stderr, "Cannot read .EXE file header\n");
- return (0L);
- }
-
- /* determine .EXE header size and step over it */
-
- if (! MoveTo (16L * (long) Header.HeaderParagraphs))
- return (0L);
-
- /* search through program file to find the copyright message */
-
- for (p = _CPPTR (); ! feof (fp); )
- {
- while ((c = fgetc (fp)) != EOF && (char) c != *p)
- ;
- if (c != EOF)
- {
- /* First character match. Save current file position and
- see if copyright found */
-
- pos = ftell (fp);
-
- for (cp = p + 1; *cp && (c = fgetc (fp)) != EOF && *cp == (char) c; ++cp)
- ;
-
- if (*cp)
- {
- /* mismatch - recover position and continue search */
-
- if (! MoveTo (pos))
- return (0L);
- }
- else
- {
- /* found - return position */
-
- return (pos - 1L);
- }
- }
- }
-
- fprintf (stderr, "\nCopyright message not found in file %s\n", TargetName);
- return (0L);
- }
-